package com.huishu.tcm.controller;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.huishu.tcm.entity.User;
import com.huishu.tcm.service.UserService;
import com.huishu.tcm.task.SessionKeyService;
import com.huishu.tcm.task.VerificationCodeService;
import com.huishu.tcm.util.AESUtil;
import com.huishu.tcm.util.Constants;
import com.huishu.tcm.util.SmsUtil;
import com.huishu.tcm.util.exception.TcmException;
import com.huishu.tcm.util.exception.TcmExceptionEnum;
import com.huishu.tcm.vo.SessionKeyVo;
import com.huishu.tcm.vo.SmsResponseVo;
import com.huishu.tcm.vo.VerificationCodeVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

@Api(tags = "权限认证")
@RestController
@RequestMapping("/api/auth")
@Slf4j
public class AuthController {

    @Resource
    UserService userService;

    // 获取验证码
    @ApiOperation(value = "获取验证码", notes = "获取验证码")
    @GetMapping(value = "/getVerificationCode", params = {"telNum"})
    public void getVerificationCode(String telNum) throws Exception{
        // 防止验证码位数不够
        long random = Math.round(Math.random() * 10000);
        if(random < 1000){
            random += 1000;
        }
        String verificationCode = String.valueOf(random);
        Date expirationDate = new Date(new Date().getTime() + 5 * 60 * 1000);
        try{
            SmsResponseVo responseVo = SmsUtil.sendSms(telNum,verificationCode);
            log.info( "发送验证码返回值：" + JSONObject.toJSONString(responseVo));
        }catch (Exception e){
            throw new TcmException(TcmExceptionEnum.SMS_SEND_ERROR);
        }
        // 删除该手机号已发送的验证码
        VerificationCodeService.removeVerificationCode(telNum);
        // 保存当前验证码
        VerificationCodeVo v = new VerificationCodeVo();
        v.setTelNum(telNum);
        v.setExpirationDate(expirationDate);
        v.setVerificationCode(verificationCode);
        VerificationCodeService.addVerificationCode(v);
    }

    @ApiOperation(value = "使用手机号验证码修改密码", notes = "使用手机号验证码修改密码")
    @GetMapping(value = "/changePwdByVerificationCode", params = {"telNum","verificationCode","password"})
    public void changePwdByVerificationCode( String telNum,  String verificationCode,  String password) throws Exception {
        // 判断验证码是否正确、是否过期
        List<VerificationCodeVo> verificationCodeVoList = VerificationCodeService.verificationCodeVoList;
        VerificationCodeVo verificationCodeVo = null;
        Date now = new Date();
        for(VerificationCodeVo v : verificationCodeVoList){
            if(v.getTelNum().equals(telNum) && v.getVerificationCode().equals(verificationCode)
                && now.before(v.getExpirationDate())){
                verificationCodeVo = v;
                break;
            }
        }
        if(verificationCodeVo == null){
            throw new TcmException(TcmExceptionEnum.USER_WRONG_VERIFICATION_CODE);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper();
        queryWrapper.eq("tel_num", telNum);
        User user = userService.getOne(queryWrapper);
        if(ObjectUtil.isEmpty(user)){
            throw new TcmException(TcmExceptionEnum.USER_ACCOUNT_NOT_EXIST);
        }
        String pwd = AESUtil.encrypt(password,AESUtil.key);
        user.setPassword(pwd);
        userService.update(user, queryWrapper);
    }

    @ApiOperation(value = "注册", notes = "医生和患者的注册接口 ，字段role值为patient、doctor")
    @PostMapping("/register")
    public void register( @RequestBody User user) throws Exception {
        // 判断验证码是否正确
        List<VerificationCodeVo> verificationCodeVoList = VerificationCodeService.verificationCodeVoList;
        VerificationCodeVo verificationCodeVo = null;
        Date now = new Date();
        for(VerificationCodeVo v: verificationCodeVoList){
            if(v.getTelNum().equals(user.getTelNum()) && v.getVerificationCode().equals(user.getVerificationCode())
                && now.before(v.getExpirationDate())){
                verificationCodeVo = v;
                break;
            }
        }
        if(verificationCodeVo == null){
            throw new TcmException(TcmExceptionEnum.USER_WRONG_VERIFICATION_CODE);
        }
        // 判断手机号是否已注册
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tel_num", user.getTelNum());
        List<User> userList = userService.list(queryWrapper);
        if(userList.size() > 0 && userList.get(0).getRegisterStatus().equals(Constants.USER_REGISTER_STATUS_success)){
            throw new TcmException(TcmExceptionEnum.DATA_ALREADY_EXISTS.getCode(), "该手机号已注册");
        }
        // 判断用户未填写性别时，默认为男
        if(!("man".equals(user.getGender()) || "woman".equals(user.getGender()))){
            user.setGender("man");
        }
        // 使用身份证数据计算年龄
        if(ObjectUtil.isNotEmpty(user.getIdNum()) && user.getIdNum().length() == 18){
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            String birthdayStr = user.getIdNum().substring(6,14);
            Date birthday = sdf.parse(birthdayStr);
            long age = (now.getTime() - birthday.getTime()) / 1000 / 60 / 60 / 24 /365;
            user.setAge(Integer.valueOf(String.valueOf(age)));
        }
        // 保存用户信息
        if(Constants.USER_ROLE_DOCTOR.equals(user.getRole())){ // 医生
            // 如果是因为审核不通过重新注册的
            if(userList.size() > 0){
                user = userList.get(0);
                user.setPassword(AESUtil.encrypt(user.getPassword(),AESUtil.key));
                user.setRegisterStatus(Constants.USER_REGISTER_STATUS_ToBeReviewed);
                user.setUpdateTime(now);
                userService.updateById(user);
            }else{
                user.setPassword(AESUtil.encrypt(user.getPassword(),AESUtil.key));
                user.setRegisterStatus(Constants.USER_REGISTER_STATUS_ToBeReviewed);
                user.setCreateTime(now);
                user.setUpdateTime(now);
                userService.save(user);
            }
        }else if(Constants.USER_ROLE_PATIENT.equals(user.getRole())){ // 患者
            user.setEndManagement(false);
            user.setPassword(AESUtil.encrypt(user.getPassword(),AESUtil.key));
            user.setRegisterStatus(Constants.USER_REGISTER_STATUS_success);
            user.setCreateTime(now);
            user.setUpdateTime(now);
            userService.save(user);
        }else{
            throw new TcmException(TcmExceptionEnum.DATA_FIELD_VALUE_IS_INCORRECT.getCode(), "用户角色错误，请确认");
        }
    }

    @ApiOperation(value = "使用验证码登录", notes = "使用验证码登录")
    @PostMapping(value = "/loginWithVerificationCode", params = {"telNum", "verificationCode","role"})
    public SaTokenInfo loginWithVerificationCode(String telNum, String verificationCode, String role) throws TcmException{
        List<VerificationCodeVo> verificationCodeVoList = VerificationCodeService.verificationCodeVoList;
        Date now = new Date();
        for(VerificationCodeVo v : verificationCodeVoList){
            // 1、判断手机号是否相同 2、判断验证码是否相同 3、判断验证码是否过期
            if(v.getTelNum().equals(telNum) && v.getVerificationCode().equals(verificationCode)
                && now.before(v.getExpirationDate())){
                QueryWrapper<User> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("tel_num",telNum);
                if(ObjectUtil.isNotEmpty(role)){
                    queryWrapper.eq("role",role);
                }else{
                    queryWrapper.eq("role",Constants.USER_ROLE_PATIENT);
                }
                User user = userService.getOne(queryWrapper);
                if(!Constants.USER_REGISTER_STATUS_success.equals(user.getRegisterStatus())){
                    throw new TcmException(TcmExceptionEnum.USER_ACCOUNT_NOT_EXIST.getCode(),"用户暂未审核或审核失败，请联系管理员。");
                }
                if(ObjectUtil.isNotEmpty(user)){
                    // 用户信息脱敏
                    AESUtil.userInfoDesensitization(user);
                    StpUtil.login(JSONObject.toJSONString(user));
                    return StpUtil.getTokenInfo();
                }
                throw new TcmException(TcmExceptionEnum.USER_ACCOUNT_NOT_EXIST);
            }
        }
        throw new TcmException(TcmExceptionEnum.USER_WRONG_VERIFICATION_CODE);
    }

    @ApiOperation(value = "使用密码登录", notes = "使用密码登录")
    @PostMapping("/login")
    public SaTokenInfo login(@RequestBody User user) throws Exception {
        if(ObjectUtil.isEmpty(user)){
            throw new TcmException(TcmExceptionEnum.USER_WRONG_ACCOUNT_PASSWORD);
        }
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("tel_num",user.getTelNum());
        if(ObjectUtil.isNotEmpty(user.getRole())){
            wrapper.eq("role",user.getRole());
        }else{
            wrapper.eq("role",Constants.USER_ROLE_PATIENT);
        }
        User u = userService.getOne(wrapper);
        if(ObjectUtil.isNotEmpty(u)){
            if(!Constants.USER_REGISTER_STATUS_success.equals(u.getRegisterStatus())){
                throw new TcmException(TcmExceptionEnum.USER_ACCOUNT_NOT_EXIST.getCode(),"用户暂未审核或审核失败，请联系管理员。");
            }
            String pwd = AESUtil.encrypt(user.getPassword(),AESUtil.key);
            if(u.getPassword().equals(pwd)){
                // 用户信息脱敏
                AESUtil.userInfoDesensitization(u);
                StpUtil.login(JSONObject.toJSONString(u));
                return StpUtil.getTokenInfo();
            }
        }
        throw new TcmException(TcmExceptionEnum.USER_WRONG_ACCOUNT_PASSWORD);
    }

    @ApiOperation(value = "退出登录", notes = "退出登录")
    @RequestMapping(value = "/logout", method = RequestMethod.GET)
    public void logout(){
        StpUtil.logout();
    }
    @ApiOperation(value = "判断是否登录", notes = "判断是否登录")
    @RequestMapping(value = "/isLogin", method = RequestMethod.GET)
    public boolean isLogin() {
        return StpUtil.isLogin();
    }


    @ApiOperation(value = "获取验证码前判断用户是否已注册", notes = "1、注册：用户审核状态为未通过或者用户不存在时可以获取验证码；2、找回密码：用户审核状态为成功时可以获取验证码")
    @GetMapping(value = "/checkIsRegister", params = {"telNum"})
    public User checkIsRegister(String telNum){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("tel_num", telNum);
        User user = userService.getOne(userQueryWrapper);
        User result = new User();
        if(ObjectUtil.isNotEmpty(user)){
            result.setTelNum(user.getTelNum());
            result.setRegisterStatus(user.getRegisterStatus());
        }
        // 用户信息脱敏
        AESUtil.userInfoDesensitization(result);
        return result;
    }

    @ApiOperation(value = "获取微信数据",notes = "获取微信数据")
    @GetMapping(value = "/jscode2session", params = {"js_code"})
    public SessionKeyVo jscode2session(String js_code){
        Map<String,Object> params = new HashMap<>();
        params.put("appid","wxfd93f373d36788fe");
        params.put("secret","8c34a88c2aae5f376841e83641009793");
        params.put("js_code",js_code);
        params.put("grant_type","authorization_code");
        String res = HttpUtil.get("https://api.weixin.qq.com/sns/jscode2session",params);
        SessionKeyVo sessionKey = JSONObject.parseObject(res, SessionKeyVo.class);
        if(ObjectUtil.isEmpty(sessionKey.getErrcode()) || sessionKey.getErrcode() == 0){
            // 添加到缓存中
            SessionKeyService.addSessionKey(sessionKey);
        }
        return sessionKey;
    }

    @ApiOperation(value = "患者微信快捷登录", notes = "患者微信快捷登录使用")
    @GetMapping(value = "/quickLoginWx", params = {"telNum","key"})
    public SaTokenInfo quickLoginWx(String telNum, String key) throws TcmException{
        if(ObjectUtil.isEmpty(telNum)){
            throw new TcmException(TcmExceptionEnum.USER_WRONG_ACCOUNT_PASSWORD.getCode(),"手机号码不可为空。");
        }
        // 判断session key是否存在
        for(SessionKeyVo v: SessionKeyService.sessionKeyVoList){
            if(v.getSession_key().equals(key)){
                QueryWrapper<User> wrapper = new QueryWrapper<>();
                wrapper.eq("tel_num",telNum);
                wrapper.eq("role",Constants.USER_ROLE_PATIENT);
                User u = userService.getOne(wrapper);
                if(ObjectUtil.isNotEmpty(u)){
                    // 用户信息脱敏
                    AESUtil.userInfoDesensitization(u);
                    StpUtil.login(JSONObject.toJSONString(u));
                    return StpUtil.getTokenInfo();
                }
                throw new TcmException(TcmExceptionEnum.USER_ACCOUNT_NOT_EXIST);
            }
        }
        throw new TcmException(TcmExceptionEnum.DATA_NOT_EXISTS);
    }
}
